﻿using System;
using System.Collections.Generic;
using System.IO.Ports;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace MainFrame
{
    public delegate bool d_sp_read_proc(string receiveStr);
    public class serialPortHelper
    {
        public d_sp_read_proc sp_Read_Proc;
        private string m_newLine = "\r\n";
        private string m_portName;//端口号
        private int m_baudRate;//波特率
        private int m_dataBits;//数据位
        private string m_stopbit;//停止位
        private string m_checkOut;//校验位
        private SerialPort m_sp=new SerialPort();//串口
        private bool b_changLine;//接收是否换行符
        private bool b_isByte;//接收是否为字节
        private string receiveDa = "";//接收到内容
        private byte[] receiveBytes;//接收的字节数据
        public bool B_changLine { get => b_changLine; set => b_changLine = value; }
        public bool B_isByte { get => b_isByte; set => b_isByte = value; }
        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="portName">串口号COM加数字，比如COM1</param>
        /// <param name="baudRate">波特率，9600，19200，38400等</param>
        /// <param name="dataBits">数据位 5，6，7，8</param>
        /// <param name="stopbit">停止位 1，1.5，2或者One、OnePointFive、Two</param>
        /// <param name="checkOut">校验位，无、奇校验、偶检验、标记、空格或者None、Odd、Even、Mark、Space</param>
        public serialPortHelper(string portName, int baudRate, int dataBits, string stopbit, string checkOut,string newLine)
        {
            m_portName = portName;
            m_baudRate = baudRate;
            m_dataBits = dataBits;
            m_stopbit = stopbit;
            m_checkOut = checkOut;
            m_newLine = newLine;
            Open(portName, baudRate, dataBits, stopbit, checkOut,newLine);
        }
        /// <summary>
        /// 打开串口
        /// </summary>
        /// <param name="portName">串口号COM加数字，比如COM1</param>
        /// <param name="baudRate">波特率，9600，19200，38400等</param>
        /// <param name="dataBits">数据位 5，6，7，8</param>
        /// <param name="stopbit">停止位 1，1.5，2或者One、OnePointFive、Two</param>
        /// <param name="checkOut">校验位，无、奇校验、偶检验、标记、空格或者None、Odd、Even、Mark、Space</param>
        public void Open(string portName,int baudRate, int dataBits,string stopbit,string checkOut, string newLine)
        {
            try
            {
                if (m_sp == null)
                {
                    m_sp = new SerialPort();
                }
                if (m_sp.IsOpen)                    //如果串口已经打开，提示
                {
                    displalyInfo.displayInfoMain?.Invoke("当前串口已打开，请勿重复打开");
                    return;
                }
                else
                {
                    if (SerialPort.GetPortNames().Length == 0)
                    {
                        displalyInfo.displayInfoMain?.Invoke("当前电脑无可用串口，请检查连接");
                        return;
                    }
                    else
                    {
                        m_sp.PortName = portName;//设置串口名称
                        m_sp.BaudRate = baudRate;//设置串口波特率
                        m_sp.DataBits = dataBits;//设置串口数据位

                        switch (stopbit)   //停止位不能像串口号直接用，而要用如下方法
                        {
                            case "One":
                                m_sp.StopBits = StopBits.One;
                                break;
                            case "1":
                                m_sp.StopBits = StopBits.One;
                                break;
                            case "1.5":
                                m_sp.StopBits = StopBits.OnePointFive;
                                break;
                            case "OnePointFive":
                                m_sp.StopBits = StopBits.OnePointFive;
                                break;
                            case "2":
                                m_sp.StopBits = StopBits.Two;
                                break;
                            case "Two":
                                m_sp.StopBits = StopBits.Two;
                                break;
                            default:
                                m_sp.StopBits = StopBits.One;
                                break;
                        }
                        switch (checkOut)
                        {
                            case "None":
                                m_sp.Parity = Parity.None;
                                break;
                            case "无":
                                m_sp.Parity = Parity.None;
                                break;
                            case "Even":
                                m_sp.Parity = Parity.Even;
                                break;
                            case "偶校验":
                                m_sp.Parity = Parity.Even;
                                break;
                            case "Odd":
                                m_sp.Parity = Parity.Odd;
                                break;
                            case "奇校验":
                                m_sp.Parity = Parity.Odd;
                                break;
                            case "Mark":
                                m_sp.Parity = Parity.Mark;
                                break;
                            case "标记":
                                m_sp.Parity = Parity.Mark;
                                break;
                            case "Space":
                                m_sp.Parity = Parity.Space;
                                break;
                            case "空格":
                                m_sp.Parity = Parity.Space;
                                break;
                            default:
                                m_sp.Parity = Parity.None;
                                break;
                        }

                        m_sp.NewLine = newLine;
                        m_sp.RtsEnable = true;
                        displalyInfo.displayInfoMain?.Invoke($"串口号：[{portName}] 、波特率：[{baudRate}] 、数据位：[{dataBits}]" +
                   $" 、停止位：[{stopbit}] 、校验位：[{checkOut}]");
                        m_sp.Open();
                        m_sp.DataReceived += Sp_DataReceived;
                        displalyInfo.displayInfoMain("串口已打开");

                    }


                }
            }
            catch (System.Exception ex)
            {
                displalyInfo.displayInfoMain("串口打开失败：" + ex.Message);
            }

        }

        /// <summary>
        /// 打开串口
        /// </summary>
        public void Open()
        {
            try
            {
                if (m_sp == null)
                {
                    m_sp = new SerialPort();
                }
                if (m_sp.IsOpen)                    //如果串口已经打开，提示
                {
                    displalyInfo.displayInfoMain?.Invoke("当前串口已打开，请勿重复打开");
                    return;
                }
                else
                {
                    if (SerialPort.GetPortNames().Length == 0)
                    {
                        displalyInfo.displayInfoMain?.Invoke("当前电脑无可用串口，请检查连接");
                        return;
                    }
                    else
                    {
                        m_sp.PortName = m_portName;//设置串口名称
                        m_sp.BaudRate = m_baudRate;//设置串口波特率
                        m_sp.DataBits = m_dataBits;//设置串口数据位

                        switch (m_stopbit)   //停止位不能像串口号直接用，而要用如下方法
                        {
                            case "One":
                                m_sp.StopBits = StopBits.One;
                                break;
                            case "1":
                                m_sp.StopBits = StopBits.One;
                                break;
                            case "1.5":
                                m_sp.StopBits = StopBits.OnePointFive;
                                break;
                            case "OnePointFive":
                                m_sp.StopBits = StopBits.OnePointFive;
                                break;
                            case "2":
                                m_sp.StopBits = StopBits.Two;
                                break;
                            case "Two":
                                m_sp.StopBits = StopBits.Two;
                                break;
                            default:
                                m_sp.StopBits = StopBits.One;
                                break;
                        }
                        switch (m_checkOut)
                        {
                            case "None":
                                m_sp.Parity = Parity.None;
                                break;
                            case "Even":
                                m_sp.Parity = Parity.Even;
                                break;
                            case "Odd":
                                m_sp.Parity = Parity.Odd;
                                break;
                            case "Mark":
                                m_sp.Parity = Parity.Mark;
                                break;
                            case "Space":
                                m_sp.Parity = Parity.Space;
                                break;
                            default:
                                m_sp.Parity = Parity.None;
                                break;
                        }

                        m_sp.NewLine = m_newLine;
                        m_sp.RtsEnable = true;
                        displalyInfo.displayInfoMain?.Invoke($"串口号：[{m_portName}] 、波特率：[{m_baudRate}] 、数据位：[{m_dataBits}]" +
                   $" 、停止位：[{m_stopbit}] 、校验位：[{m_checkOut}]");
                        m_sp.Open();
                        m_sp.DataReceived += Sp_DataReceived;
                        displalyInfo.displayInfoMain("串口已打开");
                    }
                }
            }
            catch (System.Exception ex)
            {
                displalyInfo.displayInfoMain("串口打开失败：" + ex.Message);
            }

        }
        /// <summary>
        /// 关闭串口
        /// </summary>
        public void Close()
        {
            try
            {
                if (m_sp == null)
                {
                    displalyInfo.displayInfoMain?.Invoke("当前串口存在");
                    return;
                }
                if (m_sp.IsOpen)                    //如果串口已经打开，提示
                {
                    m_sp.Close();
                }
                else
                {
                    displalyInfo.displayInfoMain?.Invoke("当前串口未打开");
                }
            }
            catch (System.Exception ex)
            {
                displalyInfo.displayInfoMain($"串口关闭失败：{ex}");
            }

        }

        /// <summary>
        /// 获取所有端口
        /// </summary>
        public static string[] getAllPort()
        {
            try
            {
                if (SerialPort.GetPortNames() ==null || SerialPort.GetPortNames().Length == 0)
                {
                    displalyInfo.displayInfoMain?.Invoke("当前电脑无可用串口，请检查连接");
                    return null;
                }
                else
                {
                    return SerialPort.GetPortNames();
                }
            }
            catch (System.Exception ex)
            {
                displalyInfo.displayInfoMain("串口打开失败：" + ex.Message);
                return null;
            }

        }
        private void Sp_DataReceived(object sender, SerialDataReceivedEventArgs e)
        {
            try
            {
                Thread.Sleep(30);
                if (b_isByte)
                {
                    receiveBytes = new byte[m_sp.BytesToRead];
                    m_sp.Read(receiveBytes, 0, m_sp.BytesToRead);
                }
                else
                {
                    if (b_changLine)
                    {
                        receiveDa = m_sp.ReadLine();
                    }
                    else
                    {
                        receiveDa = m_sp.ReadExisting();
                    }
                  
                }
                m_sp.DiscardInBuffer();
                displalyInfo.displayInfoMain?.Invoke($"串口[{m_portName}] 接收到数据：{receiveDa}" );
                sp_Read_Proc?.Invoke(receiveDa);
            
            }
            catch (Exception ex)
            {
                displalyInfo.displayInfoMain?.Invoke($"串口[{m_portName}] 接收异常：{ex}");
            }
        }

        /// <summary>
        /// 写入串口[字符串]
        /// </summary>
        /// <param name="writeStr">要写入的字符串</param>
        /// <returns></returns>
        public bool Write(string writeStr)
        {
            try
            {
                if (string.IsNullOrEmpty(writeStr))
                {

                    displalyInfo.displayInfoMain($"要写到串口的数据不能为空");
                    return false;
                }

                if (b_changLine)
                {
                    if (m_sp==null||(!m_sp.IsOpen))
                    {
                        displalyInfo.displayInfoMain($"串口-[{m_portName}]为空或者没有打开，请先打开串口再执行写操作");
                        return false;
                    }
                    else
                    {
                        m_sp.WriteLine(writeStr);
                    }
                }
                else
                {
                    m_sp.Write(writeStr);
                }
                displalyInfo.displayInfoMain($"串口-[{m_portName}]已写入内容：{writeStr}");
                return true;
            }
            catch (System.Exception ex)
            {
                displalyInfo.displayInfoMain($"串口写入出错：{ex}");
                return false;
            }

        }

        /// <summary>
        /// 写入串口[字符串]
        /// </summary>
        /// <param name="writeStr">要写入的字符串</param>
        /// <returns></returns>
        public bool Write(string writeStr,bool isChangeLine)
        {
            try
            {
                if (string.IsNullOrEmpty(writeStr))
                {

                    displalyInfo.displayInfoMain($"要写到串口的数据不能为空");
                    return false;
                }

                if (isChangeLine)
                {
                    if (m_sp == null || (!m_sp.IsOpen))
                    {
                        displalyInfo.displayInfoMain($"串口-[{m_portName}]为空或者没有打开，请先打开串口再执行写操作");
                        return false;
                    }
                    else
                    {
                        m_sp.WriteLine(writeStr);
                    }
                }
                else
                {
                    m_sp.Write(writeStr);
                }
                displalyInfo.displayInfoMain($"串口-[{m_portName}]已写入内容：{writeStr}");
                return true;
            }
            catch (System.Exception ex)
            {
                displalyInfo.displayInfoMain($"串口写入出错：{ex}");
                return false;
            }

        }
        /// <summary>
        /// 写入串口[字节数组]
        /// </summary>
        /// <param name="writeBytes">要写入的字节数组</param>
        /// <returns></returns>
        public bool Write(byte[] writeBytes)
        {
            try
            {
                if (writeBytes==null||writeBytes.Length<=0)
                {

                    displalyInfo.displayInfoMain($"要写到串口的数据不能为空");
                    return false;
                }

                if (m_sp == null || (!m_sp.IsOpen))
                {
                    displalyInfo.displayInfoMain($"串口-[{m_portName}]为空或者没有打开，请先打开串口再执行写操作");
                    return false;
                }
                else
                {
                    m_sp.Write(writeBytes, 0, writeBytes.Length);
                }
                
                displalyInfo.displayInfoMain($"串口-[{m_portName}]已写入内容：{BitConverter.ToString(writeBytes)}");
                return true;
            }
            catch (System.Exception ex)
            {
                displalyInfo.displayInfoMain($"串口写入出错：{ex}");
                return false;
            }

        }
    }

    public enum e_changeLine
    {
        r=0,
        n=1,
        rn=2,
        nr=3
    }
}
